%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Game Definition
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
gamePiece(rabbit(_)).
gamePiece(cat(_)).
gamePiece(dog(_)).
gamePiece(horse(_)).
gamePiece(camel(_)).
gamePiece(elephant(_)).

% legalMoves for goodGuy
directions([north,south,east,west]).

legalMoves(Piece, BoardPositions, Moves) :- directions(Directions), recursiveGetLegalMoves(Piece,BoardPositions,Directions, Moves,[]).

recursiveGetLegalMoves(Piece, BoardPositions,[], Moves, Moves).
recursiveGetLegalMoves(Piece, BoardPositions,[FirstD|TailD], Moves, MovesSoFar) :- isAllowed(Piece, FirstD, BoardPositions),
		recursiveGetLegalMoves(Piece,BoardPositions,TailD,Moves, [FirstD|MovesSoFar]),!.
recursiveGetLegalMoves(Piece, BoardPositions,[FirstD|TailD], Moves, MovesSoFar) :- recursiveGetLegalMoves(Piece,BoardPositions,TailD,Moves, MovesSoFar),!.

isAllowed(Piece, _, BoardPositions) :- extractCoords(Type,X,Y,Piece), isFrozen(Type,X,Y,BoardPositions), !, fail.
isAllowed(Piece, north, BoardPositions) :- extractCoords(_,X,Y, Piece), Up is Y+1, isFreeSpot(X,Up,BoardPositions).
isAllowed(Piece, south, BoardPositions) :- not(Piece = rabbit(_,_)), extractCoords(_,X,Y, Piece), Down is Y-1,isFreeSpot(X,Down,BoardPositions).
isAllowed(Piece, east, BoardPositions) :- extractCoords(_,X,Y, Piece), Right is X+1, isFreeSpot(Right,Y,BoardPositions).
isAllowed(Piece, west, BoardPositions) :- extractCoords(_,X,Y, Piece), Left is X-1, isFreeSpot(Left,Y,BoardPositions).


isFrozen(Type,X,Y,BoardPositions) :- X > 0, NextX is X-1, pieceAt(NextX,Y,Piece,BoardPositions), 
									pieceInfo(Piece,badGuy,OtherType),isStronger(OtherType, Type).

isStrongerOfTwo(cat,rabbit).
isStrongerOfTwo(dog,cat).
isStrongerOfTwo(horse,dog).
isStrongerOfTwo(camel,horse).
isStrongerOfTwo(elephant,camel).
isStronger(Type1,Type2) :- isStrongerOfTwo(Type1,Type2).
isStronger(Type1,Type2) :- isStrongerOfTwo(Type1,X), isStronger(X,Type2).
								
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Move Computation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
computeStep(StartState, Action, MaxDepth) :- 
			move(StartState, Action, Heuristic).

move(state(StartBoardLayout, _,_), score(Scorer,north), Heuristic) :- 
		canScore(goodGuy, Scorer, StartBoardLayout),!. % cut here. If we can score, there's no reason to keep expanding the tree.
move(State, action(Piece, Direction), Heuristic) :-
		bestMove(State, MaxDepth, 0, action(Piece,Direction), Heuristic).

canScore(goodGuy, rabbit(Index,6), StartState) :- getIthElement(6, StartState, Row, 0),
										rowContainsRabbitOfPlayerX(goodGuy, Row, 0, Index).
										
bestMove(state(BoardPositions, [FirstGoodGuy|RestOfGoodGuys],BadGuysList), MaxDepth, CurDepth, Action, HeuristicResult) :-
			bestMoveForPiece(FirstGoodGuy, BoardPositions, [FirstGoodGuy|RestOfGoodGuys], BadGuysList, MaxDepth, CurDepth, 0, -1, Action, Heuristic).
			
bestMoveForPiece(PieceToMove, BoardPositions, GoodGuysList, BadGuysList, MaxDepth, CurDepth, CurrentBestAction, CurrentBestHeuristic, Action, Heuristic) :-
			legalMoves(PieceToMove, BoardPositions,Moves),
			getBestMove(Moves,PieceToMove,BoardPositions, Action).

getBestMove([H|_],Piece, BoardPositions, action(Piece,H)). % TODO (ashleyp) find best move; use heuristic and calculate future states.

rowContainsRabbitOfPlayerX(X, [rabbit(X)|_], CurrentRabbitIndex, CurrentRabbitIndex).
rowContainsRabbitOfPlayerX(X, [H|T], CurrentRabbitIndex, FinalRabbitIndex) :- NextIndex is CurrentRabbitIndex+1, rowContainsRabbitOfPlayerX(X, T, NextIndex, FinalRabbitIndex).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Utilities
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pieceAt(x-coordinate, y-coordinate, BoardPositions)
pieceAt(X,Y,Piece, BoardPositions) :- utilPlayerAt(X,Y,Piece,BoardPositions, 0).

extractCoords(rabbit,X,Y,Piece) :- Piece = rabbit(X,Y).
extractCoords(cat,X,Y,Piece) :- Piece = cat(X,Y).
extractCoords(dog,X,Y,Piece) :- Piece = dog(X,Y).
extractCoords(horse,X,Y,Piece) :- Piece = horse(X,Y).
extractCoords(camel,X,Y,Piece) :- Piece = camel(X,Y).
extractCoords(elephant,X,Y,Piece) :- Piece = elephant(X,Y).